package com.mt.mall.service.good.impl;

import com.mt.common.core.utils.DateUtils;
import com.mt.common.core.utils.ESUtil;
import com.mt.common.core.utils.OrderByEntry;
import com.mt.common.system.service.AttachmentService;
import com.mt.mall.dao.good.CommodityDao;

import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.web.base.PageDTO;
import com.mt.common.core.web.base.PageResultDTO;
import com.mt.common.core.web.base.BaseEntity;
import com.mt.common.core.web.BaseService;
import com.mt.mall.service.merchant.ShopService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mt.mall.entity.good.Commodity;
import com.mt.mall.service.good.CommodityService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class CommodityServiceBean extends BaseService implements CommodityService {

    private static Logger logger = LogManager.getLogger();

	@Autowired
	private CommodityDao commodityDao;

	@Resource
	private RedisTemplate<String, List<Commodity>> redisTemplate;

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	@Autowired
	private AttachmentService attachmentService;

	private String INDEX_NAME = "commodity";
	@Autowired
	private ESUtil esUtil;

	@Autowired
	private ShopService shopsService;
	/**
	 * 根据分页参数查询商品集合
	 *
	 * @param pageDTO 分页条件
	 */
	@Override
	public PageResultDTO findCommoditys(PageDTO pageDTO){
        pageDTO.setStartIndex((pageDTO.getCurrentPage()-1)*pageDTO.getPageSize());
		//TODO:请在此校验参数的合法性
		this.validateFindCommoditys(pageDTO);
		if(this.getStoreId()!=-1){
			pageDTO.getFilters().put("shopId",this.getStoreId());
			pageDTO.getFilterTypes().put("shopId","单值");
		}
		List<Commodity> commodityDTOS = this.commodityDao.findCommoditys(pageDTO);
		Long totalCount = this.commodityDao.findCommodityTotalCount(pageDTO);
		PageResultDTO pageResultDTO = new PageResultDTO();
		pageResultDTO.setTotalCount(totalCount);
		pageResultDTO.setDatas(commodityDTOS);

		return pageResultDTO;
	}

	/**
	 * 查询全部商品集合
	 *
	 */
	@Override
	public List<Commodity> findAllCommoditys(){
		return this.commodityDao.findAllCommoditys();
	}

	/**
	 * 查询所有商品集合(只提取ID 和 Name)
	 *
	 */
	@Override
	public List<Commodity> findAllCommoditysWithIdName(){
		//TODO:请在此校验参数的合法性
		this.validateFindAllCommoditysWithIdName();
		return this.commodityDao.findAllCommoditysWithIdName();
	}

	/**
	 * 根据名称查询商品集合(只提取ID 和 Name)
	 *
	 * @param commodityName 名称
	 */
	@Override
	public List<Commodity> findCommoditysWithIdNameByName(String commodityName){
		//TODO:请在此校验参数的合法性
		this.validateFindCommoditysWithIdNameByName(commodityName);
		//TODO:缓存取对应参数
		Set<String> keys = stringRedisTemplate.keys("searchData:Commodity_where_commodityName_" + commodityName);
		List<Commodity> commoditys = new ArrayList<>();
		if (keys.isEmpty()) {
		commoditys = this.commodityDao.findCommoditysWithIdNameByName(commodityName);
		redisTemplate.opsForValue().set("searchData:Commodity_where_commodityName_" + commodityName, commoditys, 30, TimeUnit.DAYS);
		} else {
		commoditys = redisTemplate.opsForValue().get("searchData:Commodity_where_commodityName_" + commodityName);
		}
		return commoditys;
	}

	/**
	 * 根据ID查询指定的商品(只提取ID 和 Name)
	 *
	 * @param commodityId Id
	 */
	@Override
	public Commodity findCommoditysWithIdNameById(Long commodityId){
		//TODO:请在此校验参数的合法性
		this.validateFindCommoditysWithIdNameById(commodityId);
		return this.commodityDao.findCommoditysWithIdNameById(commodityId);
	}

	/**
	 * 根据ID查询指定的商品
	 *
	 * @param commodityId Id
	 */
	@Override
	public Commodity findCommodity(Long commodityId){
		//TODO:请在此校验参数的合法性
		this.validateFindCommodity(commodityId);
		return this.commodityDao.findCommodity(commodityId);
	}

	/**
	 * 根据ID查询指定的商品(包含外键)
	 *
	 * @param commodityId Id
	 */
	@Override
	public Commodity findCommodityWithForeignName(Long commodityId){
		//TODO:请在此校验参数的合法性
		this.validateFindCommodityWithForeignName(commodityId);
		return this.commodityDao.findCommodityWithForeignName(commodityId);
	}

	/**
	 * 新增商品
	 *
	 * @param commodity 实体对象
	 */
	@Override
	public Commodity saveCommodity(Commodity commodity){
		//TODO:请在此校验参数的合法性
		this.validateSaveCommodity(commodity);
		//TODO:填充公共参数
		this.setSavePulicColumns(commodity);
		commodity.setShopId(this.getStoreId());
		commodity.setShopName(this.shopsService.findShopsWithIdNameById(commodity.getShopId()).getName());
		commodity.setSaleNum(0L);
		Long rows = this.commodityDao.saveCommodity(commodity);
		if(rows != 1)
		{
			String error = "新增保存商品出错，数据库应该返回1,但返回了 "+rows;
			throw new BusinessException(error);
		}
		esUtil.insertDocument(INDEX_NAME,commodity);
		return commodity;
	}

	/**
	 * 更新商品
	 *
	 * @param commodity 实体对象
	 */
	@Override
	public Commodity updateCommodity(Commodity commodity){
		//TODO:请在此校验参数的合法性
		this.validateUpdateCommodity(commodity);
		Long rows = this.commodityDao.updateCommodity(commodity);
		if(rows != 1)
		{
			String error = "修改保存商品出错，数据库应该返回1,但返回了 "+rows+",数据可能被删除";
			throw new BusinessException(error);
		}
		esUtil.updateDocument(INDEX_NAME,commodity);
		return commodity;
	}

	/**
	 * 根据ID删除商品
	 *
	 * @param commodityId ID
	 */
	@Override
	public void deleteCommodity(Long commodityId){
		//TODO:请在此校验参数的合法性
		this.validateDeleteCommodity(commodityId);

		Map<Class<? extends BaseEntity>,EntityUsage> entityUsageMap = this.checkForeignEntity(Commodity.class, commodityId);
		if(entityUsageMap != null && entityUsageMap.size() >0){
			StringBuilder errors = new StringBuilder();
			errors.append("计划删除的数据正在被以下数引用\n");
			for(EntityUsage entityUsage : entityUsageMap.values()){
				errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
				for(Map.Entry<Long,String> entry : entityUsage.getUsageIdNames().entrySet() ){
					errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
				}
			}
			errors.append("，不能删除，请检查处理后再删除");
			throw  new BusinessException(errors.toString());
		}

		Long rows = this.commodityDao.deleteCommodity(commodityId);
		if(rows != 1){
			String error = "删除商品出错，数据可能已经被删除";
			throw new BusinessException(error);
		}
	}



	@Override
	public boolean synchronousAllData(){
		List<Commodity> allCommoditys = this.commodityDao.findAllCommoditys();
		esUtil.createIndex(INDEX_NAME);
		esUtil.patch(INDEX_NAME,"insert", allCommoditys,100);
		return true;
	}@Override
	public PageResultDTO findCommoditysInES(PageDTO pageDTO){
		pageDTO.setStartIndex((pageDTO.getCurrentPage()-1)*pageDTO.getPageSize());
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		//按照时间逆序查找
		//searchSourceBuilder.sort("createDatetime", SortOrder.DESC);

		//排序
		List<OrderByEntry> orderBys = pageDTO.getOrderBys();
		if(orderBys!=null){
			orderBys.forEach(item->{
				searchSourceBuilder.sort(item.getProperty(),"DESC".equals(item.getOrder()!=null?item.getOrder().toUpperCase():"ASC")?SortOrder.DESC:SortOrder.ASC);
			});
		}

		//查询条件
		BoolQueryBuilder bq=QueryBuilders.boolQuery();
		Map<String, Object> filters = pageDTO.getFilters();
		Map<String, String> filterTypes = pageDTO.getFilterTypes();
		Iterator<Map.Entry<String, String>> iterator = filterTypes!=null?filterTypes.entrySet().iterator():null;
		while (iterator!=null&&iterator.hasNext()){
			Map.Entry<String, String> next = iterator.next();
			String key = next.getKey();
			//String value = next.getValue().toString();
			String type=next.getValue();
			if("单值".equals(type)){
				Object value=filters.get(key);
				key=key+".keyword";
				bq.must(QueryBuilders.termQuery(key,value));
			}else if("模糊".equals(type)){
				bq.must(QueryBuilders.matchQuery(key,filters.get(key).toString().substring(1,filters.get(key).toString().length()-1)));
			}else if("区间".equals(type)){
				bq.filter(QueryBuilders.rangeQuery(key).gt(filters.get(key+"Start")).lt(filters.get(key+"End")));
			}
		}
		searchSourceBuilder.query(bq);
		PageResultDTO pageResultDTO = esUtil.selectDocumentPage(INDEX_NAME, searchSourceBuilder,pageDTO.getStartIndex().intValue(),pageDTO.getPageSize().intValue(), Commodity.class);
		return pageResultDTO;
	}

	@Override
	public void updateCommoditySaleNum(Long commodityId,int count) {
		this.commodityDao.updateCommoditySaleNum(commodityId,count);
	}

	@Override
	public List<Commodity> findHotCommodity() {
		Date date = DateUtils.getDate(new Date(), -15);
		return this.commodityDao.findHotCommodity(date);
	}

	//TODO:---------------验证-------------------

	private void validateFindCommoditys(PageDTO pageDTO) {
	//TODO:请使用下面方法添加数据过滤条件
	//		pageDTO.addFilter("creatorId",this.getLoginUserId());
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateFindCommoditysWithIdNameByName(String commodityName) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}


	private void validateFindAllCommoditysWithIdName() {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateFindCommoditysWithIdNameById(Long commodityId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateFindCommodity(Long commodityId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateFindCommodityWithForeignName(Long commodityId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateSaveCommodity(Commodity commodity) {
	//不为空判断
	if (commodity.getEid() != null || commodity.getCreatorId() != null || commodity.getCreateDatetime() != null) {
	throw new BusinessException("非法请求");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateUpdateCommodity(Commodity commodity) {
	//不为空判断
	if (commodity.getEid() == null) {
	throw new BusinessException("唯一标识不能为空");
	}
	//是否存在判断
	if (this.commodityDao.findCommodityTotalCount(PageDTO.create(Commodity.FIELD_ID, commodity.getEid())) == 0) {
	throw new BusinessException("修改的商品 " + commodity.getName() + " 不存在，修改失败，请重试或联系管理员");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	private void validateDeleteCommodity(Long commodityId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateCommodity()写法
	}

	@Override
	public boolean canDownloadAttachment(String formName, Long id) {
	return true;
	}
}
